package com.haiyou.data.common.accessor.redis.redisson.bucket;

import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;

import org.apache.commons.lang3.Validate;
import org.redisson.api.RedissonClient;

import com.haiyou.common.constants.ErrCode;
import com.haiyou.common.entity.Entity;
import com.haiyou.common.entity.PlayerEntity;
import com.haiyou.common.spring.component.LifecycleableComponent;
import com.haiyou.common.util.check.Assert;
import com.haiyou.common.util.object.ClassUtils;
import com.haiyou.common.util.reflect.AnnotationFinder;
import com.haiyou.data.common.accessor.Accessor;
import com.haiyou.data.common.accessor.annotation.BucketAccessorType;
import com.haiyou.data.common.accessor.annotation.CachedPolicy;
import com.haiyou.data.common.accessor.caffeine.CaffeineRedissonBucketAccessor;
import com.haiyou.data.common.persister.mysql.persister.Persister;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;


/**
 * 
 * 
 * @Description: bucket 操作类
 * @author xingyuan
 * @date 2022年12月2日 下午9:56:17
 */
@Slf4j
public abstract class BucketAccessor<V extends Entity<String>> implements LifecycleableComponent,Accessor<String, V>{
	
	@Getter
	private RedissonBucketAccessor<V> accessor;
	
	@SuppressWarnings("unchecked")
	@Override
	public void init() {
		
		//初始化
		CachedPolicy policy = AnnotationFinder.findAnnotation(getClass(), CachedPolicy.class);
		
		BucketAccessorType accessorType = policy.accessorType();
		
		switch (accessorType.value()) {
		case BucketAccessorType.REDIS_ACCESSOR:
			accessor = createRedissonBucketAccessor() ;
			break;
		case BucketAccessorType.CAFFEINE_REDIS_ACCESSOR:
			accessor = createCaffeineRedissonBucketAccessor();
			break;
		default:
			Assert.isTrue(false, ErrCode.NONE_KNOW_ERROR);
			return ;
		}
		
		accessor.init();
		
		Accessor<String,V> old = (Accessor<String,V>) pool.put(getValueClass(), this);
		
		if(old != null) {
			if(old instanceof BucketAccessor) {
				Validate.isTrue(false, "重复注册[%s]数据存储器[%s],old=%s", getValueClass(), this, old);
			}
		}

		log.debug("init {},accessor type {}",this.getClass().getSimpleName(),accessor.getClass().getSimpleName());
	}
	
	
	
	
	/**
	 * 创建 RedissonBucketAccessor
	 * @return
	 */
	public RedissonBucketAccessor<V> createRedissonBucketAccessor(){
		
		Class<?> classs = this.getClass();
		Class<V> valueClassz = this.getValueClass();
		
		RedissonBucketAccessor<V> accessor = new RedissonBucketAccessor<V>() {
			@Override
			public Class<?> getInitClass() {
				this.initClass = classs;
				return classs;
			}

			@Override
			public Class<String> getKeyClass() {
				return String.class;
			}

			@Override
			public Class<V> getValueClass() {
				return valueClassz;
			}
		};
		return accessor;
	}
	
	/**
	 * 创建 CaffeineRedissonBucketAccessor
	 * @return
	 */
	public CaffeineRedissonBucketAccessor<V> createCaffeineRedissonBucketAccessor() {
		
		Class<?> classs = this.getClass();
		Class<V> valueClassz = this.getValueClass();
		
		Assert.isTrue(ClassUtils.findAllClasses(valueClassz).contains(PlayerEntity.class), ErrCode.NONE_KNOW_ERROR,
				"CaffeineRedissonBucketAccessor need value class implements PlayerEntity,value class {}",valueClassz.getSimpleName());
		
		CaffeineRedissonBucketAccessor<V> accessor = new CaffeineRedissonBucketAccessor<V>() {

			@Override
			public Class<?> getInitClass() {
				this.initClass = classs;
				return classs;
			}

			@Override
			public Class<String> getKeyClass() {
				return String.class;
			}

			@Override
			public Class<V> getValueClass() {
				return valueClassz;
			}

		};
		return accessor;
	}

	
	public void destory() {
		accessor.destory();
	}

	
	public Map<String, V> getAll(Iterable<? extends String> keys) {
		return accessor.getAll(keys);
	}

	
	public boolean containsKey(Object key) {
		return accessor.containsKey(key);
	}

	
	public boolean containsValue(Object value) {
		return accessor.containsValue(value);
	}

	public V get(Object key) {
		return accessor.get(key);
	}
	
	/**
	 * 从redis 中获取
	 * @param key
	 * @return
	 */
	public V getRedis(Object key) {
		
		if(accessor instanceof CaffeineRedissonBucketAccessor) {
			//需要直接从redis 中获取,并更新数据
			return ((CaffeineRedissonBucketAccessor<V>)accessor).getRedis(key);
		}
		
		return accessor.get(key);
	}

	
	public V put(String key, V value) {
		return accessor.put(key, value);
	}

	
	public V remove(Object key) {
		return accessor.remove(key);
	}

	
	public void removeAll(Iterable<? extends String> keys) {
		accessor.removeAll(keys);
	}

	
	public void putAll(Map<? extends String, ? extends V> m) {
		accessor.putAll(m);
	}

	
	public V putIfAbsent(String key, V value) {
		return accessor.putIfAbsent(key, value);
	}

	
	public boolean remove(Object key, Object value) {
		return accessor.remove(key, value);
	}

	
	public boolean replace(String key, V oldValue, V newValue) {
		return accessor.replace(key, oldValue, newValue);
	}

	
	public V replace(String key, V value) {
		return accessor.replace(key, value);
	}

	
	public V computeIfAbsent(String key, Function<? super String, ? extends V> mappingFunction) {
		return accessor.computeIfAbsent(key, mappingFunction);
	}

	
	public V computeIfPresent(String key, BiFunction<? super String, ? super V, ? extends V> remappingFunction) {
		return accessor.computeIfPresent(key, remappingFunction);
	}

	
	public V compute(String key, BiFunction<? super String, ? super V, ? extends V> remappingFunction) {
		return accessor.compute(key, remappingFunction);
	}
	
	
	public V merge(String key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
		return accessor.merge(key, value, remappingFunction);
	}

	public String generateKey() {
		return accessor.generateKey();
	}
	
	
	@SuppressWarnings("unchecked")
	public Class<V> getValueClass() {
		Class<?>[] cls = ClassUtils.getTypeArguments(this.getClass());
		return (Class<V>) (cls.length == 2 ? cls[1] : cls[0]);
	}
	
	public Class<String> getKeyClass() {
		return String.class;
	}
	
	public V get(String key, Function<? super String, ? extends V> mappingFunction) {
		return accessor.get(key, mappingFunction);
	}
	
	public String getKeyPrefix() {
		return accessor.getKeyPrefix();
	}
	
	public RedissonClient getRedissonClient() {
		return accessor.getRedissonClient();
	}


	public long idMax() {
		return accessor.idAutoCreator().get();
	}
	
	@Override
	public V generate(Consumer<V> consumer) {
		return accessor.generate(consumer);
	}


	@Override
	public Class<?> getInitClass() {
		return accessor.getInitClass();
	}


	/**
	 * 获取db 操作类
	 * @return
	 */
	public Persister<String,V> getPersister(){
		return accessor.getPersister();
	}

	@Override
	public int getOrder() {
		return accessor_order;
	}
	
	
	
}
